#!/usr/bin/env python
# encoding: utf-8
__author__ = 'Gary_Zhang'

import numpy as np
from sklearn.model_selection import train_test_split  # 划分数据集
from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC
import pandas as pd  # for reading csv files
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt


class SVM:
    '''
    Using SVM to train the dataset
    best acc: 0.82
    '''

    def __init__(self, feature_columns=[], decision_function_shape='ovo'):
        self.data = pd.read_csv('../data/train/training_data_svm.csv', sep=',')
        # print(self.data)
        self.train_data = self.Normalization()  # 数据集
        # print(self.train_data.shape)

        if len(feature_columns) == 0:
            self.train_labels = self.data.iloc[:, -1]  # 标签
            self.test = pd.read_csv('../data/test/songs_to_classify.csv', sep=',')
        else:
            column_indices_to_delete = [self.data.columns.get_loc(col) for col in feature_columns]
            self.train_data = np.delete(self.train_data, column_indices_to_delete, axis=1)
            self.train_labels = self.data.iloc[:, -1]  # 标签
            # print(self.train_data)
            self.test = pd.read_csv('../data/test/songs_to_classify.csv', sep=',')
            scaler = MinMaxScaler()
            self.test = scaler.fit_transform(self.test)
            print(self.test.shape)
            self.test = np.delete(self.test, column_indices_to_delete, axis=1)

        self.shape = decision_function_shape
        self.SVM_test()
        self.Normalization()
        # self.Predict()

    def plot(self, x_train, x_test, y_train, y_test):
        # 将训练集和测试集的数据和标签合并
        x_all = np.concatenate((x_train, x_test), axis=0)
        y_all = np.concatenate((y_train, y_test), axis=0)

        # 创建一个三维图形窗口
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')

        # 根据分类标签绘制不同颜色的散点图
        unique_labels = np.unique(y_all)
        colors = ['r', 'g', 'b', 'y']  # 可以设置自定义的颜色列表
        for label, color in zip(unique_labels, colors):
            # 获取属于当前分类的数据点
            data_points = x_all[y_all == label]
            # 提取三个特征维度
            x = data_points[:, 0]
            y = data_points[:, 1]
            z = data_points[:, 2]
            # 绘制散点图
            ax.scatter(x, y, z, c=color, label=label)

        # 设置坐标轴标签
        ax.set_xlabel('Feature 1')
        ax.set_ylabel('Feature 2')
        ax.set_zlabel('Feature 3')

        # 添加图例
        ax.legend()

        # 显示图形
        plt.show()

    def SVM_test(self):
        x_train, x_test, y_train, y_test = train_test_split(self.train_data, self.train_labels,
                                                            test_size=0.3)  # 将数据集划分为训练集和测试集， 比例0.3
        svm = SVC(decision_function_shape='ovo', kernel='rbf')
        svm.fit(x_train, y_train)
        score = svm.score(x_test, y_test)
        print("准确度：", score)

        self.plot(x_train, x_test, y_train, y_test)

        self.svm_model = svm
        svm.fit(self.train_data, self.train_labels)

        scores = cross_val_score(svm, self.train_data, self.train_labels, cv=5,
                                 scoring='accuracy')  # 采用K折交叉验证的方法来验证算法效果
        print('K折准确度:', scores)

    def Normalization(self):
        features = self.data.iloc[:, :-1]
        # 特征正则化
        scaler = MinMaxScaler()
        normalized_features = scaler.fit_transform(features)
        return normalized_features

    def Predict(self):
        X_test = self.test.values
        # 特征正则化
        scaler = MinMaxScaler()
        normalized_X_test = scaler.fit_transform(X_test)

        predictions = self.svm_model.predict(X=normalized_X_test).reshape(-1, 1).astype(int).reshape(1, -1)
        print(predictions)
        return predictions




if __name__ == '__main__':

    SVM()
    # feature_columns = list(
    #     ["acousticness", "danceability", "duration", "energy", "instrumentalness", "key", "liveness", "loudness",
    #      "mode", "speechiness", "tempo", "time_signature", "valence"])  # 指定要删除的特征列

    feature_columns = list(
        ["acousticness", "danceability", "duration", "energy", "liveness", "loudness",
         "mode", "speechiness", "tempo", "time_signature"])  # 指定要删除的特征列

    worst_feature = None
    highest_accuracy = 0.0
    feature_names = []  # 存储特征名称
    mean_accuracies = []  # 存储准确率

    for column in feature_columns:
        svm = SVM(feature_columns=[column])
        scores = cross_val_score(svm.svm_model, svm.train_data, svm.train_labels, cv=5, scoring='accuracy')
        mean_accuracy = scores.mean()

        print("-----------------------------------------------")
        print(column)
        print(svm.train_data.shape)
        print(mean_accuracy)
        print("-----------------------------------------------")

        feature_names.append(column)
        mean_accuracies.append(mean_accuracy)

        if mean_accuracy > highest_accuracy:
            highest_accuracy = mean_accuracy
            worst_feature = column

    print("最不好的特征列：", worst_feature)
    print("删除后的准确率：", highest_accuracy)

    # 绘制柱状图
    plt.bar(feature_names, mean_accuracies)

    worst_feature_index = feature_names.index(worst_feature)
    plt.bar(worst_feature_index, mean_accuracies[worst_feature_index], color='red')

    plt.xlabel('Feature')
    plt.ylabel('Mean Accuracy')
    plt.title('Mean Accuracy for Each Feature')
    plt.xticks(rotation=45)  # 旋转 x 轴刻度标签，以避免重叠
    plt.tight_layout()  # 调整图像布局
    plt.show()
